package com.cmic.rcs.emoji.service.impl;

import com.cmic.rcs.emoji.common.Constant;
import com.cmic.rcs.emoji.entity.dto.ChangePasswordRequest;
import com.cmic.rcs.emoji.entity.dto.LoginRequest;
import com.cmic.rcs.emoji.entity.pojo.TAdmin;
import com.cmic.rcs.emoji.entity.vo.AdminLoginResponse;
import com.cmic.rcs.emoji.mapper.TAdminMapper;
import com.cmic.rcs.emoji.service.ITAdminService;
import com.cmic.rcs.emoji.util.CaptchaUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

import static com.cmic.rcs.emoji.common.Constant.REDIS_CAPTCHA_KEY_PREFIX;

/**
 * <p>
 * 管理员表 服务实现类
 * </p>
 *
 * @author 孙高明
 * @since 2025-10-09
 */
@Service
@Slf4j
public class TAdminServiceImpl implements ITAdminService {
    @Autowired
    protected TAdminMapper tAdminMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public AdminLoginResponse login(LoginRequest request) {
        // 1. 校验手机号格式（11位数字）
        String adminAccount = request.getAdminAccount();
        if (!adminAccount.matches("^\\d{11}$")) {
            throw new RuntimeException("手机号格式错误");
        }
        // 2. 校验验证码
        String code = redisTemplate.opsForValue().get(REDIS_CAPTCHA_KEY_PREFIX + request.getCaptchaKey());
        if (!CaptchaUtils.validateCode(request.getCaptchaCode(), code)) {
            throw new RuntimeException("验证码错误");
        }
        // 3. 根据账号查询管理员信息
        TAdmin tAdmin = tAdminMapper.selectByAccount(adminAccount);
        if (tAdmin == null) {
            throw new RuntimeException("管理员不存在");
        }
        // 5. 检查账号是否被锁定
        checkAccountLockStatus(tAdmin);
        // 6. 校验密码
        String adminPasswd = request.getAdminPasswd();
        //md5加密
        String pass = DigestUtils.md5DigestAsHex(adminPasswd.getBytes());
        log.info("密码：{}", pass);
        if (!tAdmin.getAdminPasswd().equals(pass)) {
            handlePasswordError(tAdmin);
            throw new RuntimeException("密码错误，剩余尝试次数：" + (Constant.MAX_LOGIN_FAIL_COUNT - tAdmin.getLoginFailCount()));
        }
        // 7. 重置登录失败次数
        resetLoginFailCount(tAdmin);

        // 8. 更新登录时间
        updateLastLoginTime(tAdmin);

        // 9. 检查密码是否过期或即将过期
        Integer passwordExpireDays = checkPasswordExpiration(tAdmin);

        // 10. 返回登录响应
        return new AdminLoginResponse(
                tAdmin.getAdminName(),
                tAdmin.getAdminAccount(),
                tAdmin.getLastLoginTime().toString(),
                passwordExpireDays
        );


    }

    // 修改密码
    @Override
    public void changePassword(String adminAccount, ChangePasswordRequest request) {
        log.info("管理员修改密码:");

        // 1. 查询管理员信息
        TAdmin tAdmin = tAdminMapper.selectByAccount(adminAccount);
        if (tAdmin == null) {
            throw new RuntimeException("管理员不存在");
        }


        // 2. 校验管理员状态
        if (tAdmin.getAdminStatus() != 1) {
            throw new RuntimeException("管理员状态异常，无法修改密码");
        }


        String currentPassword = DigestUtils.md5DigestAsHex(request.getCurrentPassword().getBytes());
        // 3. 校验当前密码是否正确
        if (!tAdmin.getAdminPasswd().equals(currentPassword)){
            throw new RuntimeException("当前密码错误");
        }

        // 4. 校验新密码和确认密码是否一致
        if (!request.getNewPassword().equals(request.getConfirmPassword())) {
            throw new RuntimeException("两次输入的新密码不一致");
        }

        // 5. 校验新密码是否与旧密码相同
        if (request.getNewPassword().equals(request.getCurrentPassword())) {
            throw new RuntimeException("新密码不能与当前密码相同");
        }

        // 6. 更新密码(加密)
        tAdmin.setAdminPasswd(DigestUtils.md5DigestAsHex(request.getNewPassword().getBytes()));

        // 7. 更新密码修改时间
        tAdmin.setLastPasswordChangeTime(LocalDateTime.now());

        // 8. 重置登录失败次数
        tAdmin.setLoginFailCount(0);

        // 9. 重置登录天数为90天
        tAdmin.setLastLoginTime(LocalDateTime.now().minusDays(Constant.PASSWORD_EXPIRE_DAYS));

        // 10. 保存修改
        tAdminMapper.updateById(tAdmin);


        log.info("管理员密码修改成功");
    }

    /**
     * 检查账号是否被锁定
     */
    private void checkAccountLockStatus(TAdmin tAdmin) {
        if (tAdmin.getLockTime() != null &&
                tAdmin.getLockTime().isAfter(LocalDateTime.now().minusMinutes(Constant.ACCOUNT_LOCK_MINUTES))) {
            long minutesLeft = ChronoUnit.MINUTES.between(LocalDateTime.now(), tAdmin.getLockTime().plusMinutes(Constant.ACCOUNT_LOCK_MINUTES));
            throw new RuntimeException("账号已被锁定，请" + minutesLeft + "分钟后再试");
        }
        // 如果锁定时间已过，重置锁定状态
        if (tAdmin.getLockTime() != null &&
                tAdmin.getLockTime().isBefore(LocalDateTime.now().minusMinutes(Constant.ACCOUNT_LOCK_MINUTES)))   // 如果锁定时间已过，重置锁定状态
        {
            tAdmin.setLockTime(null);
            tAdmin.setLoginFailCount(0);
            tAdminMapper.updateById(tAdmin);
        }
    }
    /**
     * 处理密码错误
     */
    private void handlePasswordError(TAdmin tAdmin) {
        int failCount = tAdmin.getLoginFailCount() == null ? 0 : tAdmin.getLoginFailCount() + 1; // 登录失败次数+1
        tAdmin.setLoginFailCount(failCount);

        // 如果达到最大失败次数，锁定账号
        if (failCount >= Constant.MAX_LOGIN_FAIL_COUNT) {
            tAdmin.setLockTime(LocalDateTime.now());
            tAdminMapper.updateById(tAdmin);
            throw new RuntimeException("密码错误次数过多，账号已被锁定" + Constant.ACCOUNT_LOCK_MINUTES + "分钟");
        }

        tAdminMapper.updateById(tAdmin);
    }
    /**
     * 重置登录失败次数
     */
    private void resetLoginFailCount(TAdmin tAdmin) {
        if (tAdmin.getLoginFailCount() != null && tAdmin.getLoginFailCount() > 0) {
            tAdmin.setLoginFailCount(0);
            tAdminMapper.updateById(tAdmin);
        }
    }

    /**
     * 更新登录时间
     */
    private void updateLastLoginTime(TAdmin tAdmin) {
        tAdmin.setLastLoginTime(LocalDateTime.now());
        tAdminMapper.updateById(tAdmin);
    }

    /**
     * 检查密码是否过期或即将过期
     */
    private Integer checkPasswordExpiration(TAdmin tAdmin) {
        if (tAdmin.getLastPasswordChangeTime() == null) {
            // 如果从未修改过密码，设置默认过期时间
            tAdmin.setLastPasswordChangeTime(LocalDateTime.now());
            tAdminMapper.updateById(tAdmin);
            return Constant.PASSWORD_EXPIRE_DAYS;
        }

        // 计算密码已使用的天数
        long daysSinceLastChange = ChronoUnit.DAYS.between(tAdmin.getLastPasswordChangeTime(), LocalDateTime.now());
        // 计算密码剩余天数
        long daysUntilExpire = Constant.PASSWORD_EXPIRE_DAYS - daysSinceLastChange;

        // 检查密码是否过期
        if (daysUntilExpire <= 0) {
            throw new RuntimeException("密码已过期，请联系管理员重置密码");
        }

        // 检查密码是否即将过期
        if (daysUntilExpire <= Constant.PASSWORD_WARNING_DAYS) {
            // 返回剩余天数，前端可以显示提示
            return (int) daysUntilExpire;
        }

        return Math.toIntExact(daysUntilExpire);
    }
}
